/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.iwords.alipay;

import com.alipay.services.AlipayService;
import com.alipay.util.AlipayNotify;
import com.iwords.service.AccountServiceLocal;
import com.iwords.service.TeacherService;
import com.iwords.service.UserServiceLocal;
import com.iwords.service.object.AccountEntity;
import com.iwords.service.object.TeacherEntity;
import com.iwords.service.object.UserEntity;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author sunmellon
 */
@WebServlet(name = "IWordsAlipayServlet", urlPatterns = {"/alipayStart", "/alipayTo", "/alipayDiscount", "/alipayReturn", "/alipayNotify"})
public class IWordsAlipayServlet extends HttpServlet {

    /** 
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("request.getPathInfo() = " + request.getPathInfo());
        System.out.println("request.getServletPath() = " + request.getServletPath());
        String servletPath = request.getServletPath();
        System.out.println("processRequest(request, response) servletPath = " + servletPath);
        if ("/alipayStart".equals(servletPath)) {
            System.out.println("alipayStart(request, response);");
            alipayStart(request, response);
        } else if ("/alipayTo".equals(servletPath)) {
            System.out.println("alipayTo(request, response);");
            alipayTo(request, response);
        } else if ("/alipayDiscount".equals(servletPath)) {
            System.out.println("alipayDiscount(request, response);");
            alipayDiscount(request, response);
        } else if ("/alipayReturn".equals(servletPath)) {
            System.out.println("alipayReturn(request, response);");
            alipayReturn(request, response);
        } else if ("/alipayNotify".equals(servletPath)) {
            System.out.println("alipayNotify(request, response);");
            alipayNotify(request, response);
        } else {
            System.out.println("non(request, response); servletPath = " + servletPath);
        }
    }

    /**
     * 用户请求支付，打开填写优惠券表单.
     * 提交后生成订单，订单存入数据库，
     * 向支付宝发出支付请求。
     */
    void alipayStart(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("IWordsAlipayServlet.alipayStart()");
        /*
        TeacherEntity maggie = new TeacherEntity();
        maggie.setTeachername("Maggie");
        maggie.setMarketingid("maggie");
        maggie.setCreatetime(new java.util.Date(System.currentTimeMillis()));
        maggie.setUpdatetime(new java.util.Date(System.currentTimeMillis()));
        maggie.setStatus(1);
        teacherService.create(maggie);
        
        TeacherEntity juliet = new TeacherEntity();
        juliet.setTeachername("Juliet");
        juliet.setMarketingid("juliet");
        juliet.setCreatetime(new java.util.Date(System.currentTimeMillis()));
        juliet.setUpdatetime(new java.util.Date(System.currentTimeMillis()));
        juliet.setStatus(1);
        teacherService.create(juliet);
         */
        System.out.println("IWordsAlipayServlet.alipayStart() teacher created!");
        getServletContext().getRequestDispatcher("/alipayStart.jsp").forward(request, response);
    }
    
    
    @EJB
    AccountServiceLocal accountService;
    @EJB
    UserServiceLocal userService;    
    //@EJB
    //AccountService accountServiceRemote;

    /**
     * 用户请求支付，提交后生成订单，订单存入数据库，
     * 向支付宝发出支付请求。
     */
    void alipayTo(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("IWordsAlipayServlet.alipayTo()");
        String feeParam = request.getParameter("total_fee");
        Integer amount = null;
        try {
            amount = new Float((100 * Float.parseFloat(feeParam))).intValue();
        } catch (Exception e) {
            request.setAttribute("errMessage", "支付金额解析有误：" + e.getMessage());
            getServletContext().getRequestDispatcher("/alipayError.jsp").forward(request, response);
            return;
        }
        UserEntity user = (UserEntity) request.getSession().getAttribute("user");
        if(user == null){
            getServletContext().getRequestDispatcher("/login.jsp").forward(request, response);
            return;
        }
        //生成爱词订单，订单号是调用支付宝支付接口的必备参数
        AccountEntity account = new AccountEntity();
        account.setUserid(user.getUserid());
        account.setAccountamt(amount);
        //account.setAlipayNumber();
        account.setCreatetime(new java.util.Date(System.currentTimeMillis()));
        account.setUpdatetime(new java.util.Date(System.currentTimeMillis()));
        account.setStatus(0);//0表示新建，1表示成功
        accountService.create(account);

        ////////////////////////////////////请求参数//////////////////////////////////////

        //必填参数//

        //请与贵网站订单系统中的唯一订单号匹配
        String out_trade_no = account.getId() + "";//
        //订单名称，显示在支付宝收银台里的“商品名称”里，显示在支付宝的交易管理的“商品名称”的列表里。
        //String subject = new String(request.getParameter("subject").getBytes("ISO-8859-1"), "utf-8");
        String subject = request.getParameter("subject");
        //订单描述、订单详细、订单备注，显示在支付宝收银台里的“商品描述”里
        String body = "爱词－软件技术服务费。";//new String(request.getParameter("alibody").getBytes("ISO-8859-1"),"utf-8");
        //订单总金额，显示在支付宝收银台里的“应付总额”里
        String total_fee = feeParam;


        //扩展功能参数——默认支付方式//

        //默认支付方式，取值见“即时到帐接口”技术文档中的请求参数列表
        String paymethod = "";
        //默认网银代号，代号列表见“即时到帐接口”技术文档“附录”→“银行列表”
        String defaultbank = "";

        //扩展功能参数——防钓鱼//

        //防钓鱼时间戳
        String anti_phishing_key = "";
        //获取客户端的IP地址，建议：编写获取客户端IP地址的程序
        String exter_invoke_ip = request.getRemoteAddr();
        //注意：
        //1.请慎重选择是否开启防钓鱼功能
        //2.exter_invoke_ip、anti_phishing_key一旦被设置过，那么它们就会成为必填参数
        //3.开启防钓鱼功能后，服务器、本机电脑必须支持远程XML解析，请配置好该环境。
        //4.建议使用POST方式请求数据
        //示例：
        //anti_phishing_key = AlipayService.query_timestamp();	//获取防钓鱼时间戳函数
        //exter_invoke_ip = "202.1.1.1";

        //扩展功能参数——其他///

        //自定义参数，可存放任何内容（除=、&等特殊字符外），不会显示在页面上
        String extra_common_param = "";
        //默认买家支付宝账号
        String buyer_email = "";
        //商品展示地址，要用http:// 格式的完整路径，不允许加?id=123这类自定义参数
        String show_url = "http://www.5iwords.com";

        //扩展功能参数——分润(若要使用，请按照注释要求的格式赋值)//

        //提成类型，该值为固定值：10，不需要修改
        String royalty_type = "";
        //提成信息集
        String royalty_parameters = "";
        //注意：
        //与需要结合商户网站自身情况动态获取每笔交易的各分润收款账号、各分润金额、各分润说明。最多只能设置10条
        //各分润金额的总和须小于等于total_fee
        //提成信息集格式为：收款方Email_1^金额1^备注1|收款方Email_2^金额2^备注2
        //示例：
        //royalty_type = "10"
        //royalty_parameters	= "111@126.com^0.01^分润备注一|222@126.com^0.01^分润备注二"

        //////////////////////////////////////////////////////////////////////////////////

        //把请求参数打包成数组
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("payment_type", "1");
        sParaTemp.put("out_trade_no", out_trade_no);
        sParaTemp.put("subject", subject);
        sParaTemp.put("body", body);
        sParaTemp.put("total_fee", total_fee);
        sParaTemp.put("show_url", show_url);
        sParaTemp.put("paymethod", paymethod);
        sParaTemp.put("defaultbank", defaultbank);
        sParaTemp.put("anti_phishing_key", anti_phishing_key);
        sParaTemp.put("exter_invoke_ip", exter_invoke_ip);
        sParaTemp.put("extra_common_param", extra_common_param);
        sParaTemp.put("buyer_email", buyer_email);
        sParaTemp.put("royalty_type", royalty_type);
        sParaTemp.put("royalty_parameters", royalty_parameters);

        System.out.println("IWordsAlipayServlet.alipayTo() sParaTemp = " + sParaTemp);

        //构造函数，生成请求URL
        String alipayHTML = AlipayService.create_direct_pay_by_user(sParaTemp);
        System.out.println("IWordsAlipayServlet.alipayTo() alipayHTML = " + alipayHTML);
        request.setAttribute("alipayHTML", alipayHTML);
        getServletContext().getRequestDispatcher("/alipayTo.jsp").forward(request, response);
    }

    /**
     * 用户支付成功后，支付宝同步回调逻辑。
     * 以下是支付宝提供的api接口中jsp方式相应的说明：
     * 
     * 功能：支付宝页面跳转同步通知页面
     * 版本：3.2
     * 日期：2011-03-17
     * 说明：
     * 以下代码只是为了方便商户测试而提供的样例代码，商户可以根据自己网站的需要，按照技术文档编写,并非一定要使用该代码。
     * 该代码仅供学习和研究支付宝接口使用，只是提供一个参考。
     * //***********页面功能说明***********
     * 该页面可在本机电脑测试
     * 可放入HTML等美化页面的代码、商户业务逻辑程序代码
     * TRADE_FINISHED(表示交易已经成功结束，为普通即时到帐的交易状态成功标识);
     * TRADE_SUCCESS(表示交易已经成功结束，为高级即时到帐的交易状态成功标识);
     * 
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    void alipayReturn(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("IWordsAlipayServlet.alipayReturn()");

        //获取支付宝GET过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
            params.put(name, valueStr);
        }


        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//

        String trade_no = request.getParameter("trade_no");//支付宝交易号
        String order_no = request.getParameter("out_trade_no");//获取订单号
        String total_fee = request.getParameter("total_fee");//获取总金额
        System.out.println("trade_no = "+trade_no);
        System.out.println("order_no = "+order_no);
        System.out.println("total_fee = "+total_fee);
        String subject = new String(request.getParameter("subject").getBytes("ISO-8859-1"), "utf-8");//商品名称、订单名称
        String body = "";
        if (request.getParameter("body") != null) {
            body = new String(request.getParameter("body").getBytes("ISO-8859-1"), "utf-8");//商品描述、订单备注、描述
        }
        String buyer_email = request.getParameter("buyer_email");//买家支付宝账号
        System.out.println("buyer_email = "+buyer_email);
        String trade_status = request.getParameter("trade_status");//交易状态

        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//

        //计算得出通知验证结果
        boolean verify_result = AlipayNotify.verify(params);
        
        if (verify_result) {//验证成功
            System.out.println("验证成功。");
            //////////////////////////////////////////////////////////////////////////////////////////
            //请在这里加上商户的业务逻辑程序代码
            System.out.println("trade_status="+trade_status);
            if(order_no != null){
                AccountEntity account = accountService.find(Long.valueOf(order_no));
                account.setAlipayNumber(trade_no);
                account.setAlipayEmail(buyer_email);
                accountService.edit(account);
            }
            //——请根据您的业务逻辑来编写程序（以下代码仅作参考）——

            if (trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {
                //判断该笔订单是否在商户网站中已经做过处理（可参考“集成教程”中“3.4返回数据处理”）
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                //如果有做过处理，不执行商户的业务程序
                AccountEntity account = new AccountEntity();
                account.setId(Long.valueOf(order_no));
                account.setAlipayEmail(buyer_email);
                account.setAlipayNumber(trade_no);
                if(accountService.updateAccountForAlipay(account)){
                    //更新session
                    Object o = request.getSession().getAttribute("user");
                    if(o!=null){
                        UserEntity user = (UserEntity)o;
                        user = userService.find(user.getUserid());
                        request.getSession().setAttribute("user", user);
                    }
                    
                   request.setAttribute("message", "付款成功，祝您天天向上。支付宝交易号："+trade_no); 
                }else{
                    request.setAttribute("message", "支付宝付款异常，请咨询爱词管理员。支付宝交易号："+trade_no);
                }
            }else{
                request.setAttribute("message", "错误的请求参数，请咨询支付宝。支付宝交易号："+trade_no);
            }

            //该页面可做页面美工编辑
            //out.println("验证成功<br />");
            //out.println("trade_no=" + trade_no);

            //——请根据您的业务逻辑来编写程序（以上代码仅作参考）——
            
            //////////////////////////////////////////////////////////////////////////////////////////
        } else {
            //该页面可做页面美工编辑
            //out.println("验证失败");
            request.setAttribute("message", "付款失败，请咨询支付宝。支付宝交易号："+trade_no);
        }

        getServletContext().getRequestDispatcher("/alipayReturn.jsp").forward(request, response);
    }
    @EJB
    TeacherService teacherService;

    /**
     * 判断推广Id的正确性。
     * 
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    void alipayDiscount(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //System.out.println("alipayDiscount(request,response) discountId = "+request.getParameter("discountId"));
        response.setContentType("text/plain;charset=UTF-8");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        PrintWriter out = response.getWriter();
        try {
            String discountId = request.getParameter("discountId");
            if (discountId != null || discountId.length() > 0) {
                TeacherEntity teacher = new TeacherEntity();
                teacher.setMarketingid(discountId);
                if (teacherService.isContain(teacher)) {
                    out.println("{\"success\":true}");
                    //System.out.println("{\"success\":true}");
                    return;
                }
            }
            out.println("{\"success\":false}");
            //System.out.println("{\"success\":false}");
        } finally {
            out.close();
        }
    }

    /**
     * 用户支付成功后，支付宝异步回调逻辑。
     * 
     * 以下是支付宝提供的api接口中jsp方式相应的说明：
     * 
     * 功能：支付宝服务器异步通知页面
     * 版本：3.2
     * 日期：2011-03-17
     * 说明：
     * 以下代码只是为了方便商户测试而提供的样例代码，商户可以根据自己网站的需要，按照技术文档编写,并非一定要使用该代码。
     * 该代码仅供学习和研究支付宝接口使用，只是提供一个参考。
     * **********页面功能说明***********
     * 创建该页面文件时，请留心该页面文件中无任何HTML代码及空格。
     * 该页面不能在本机电脑测试，请到服务器上做测试。请确保外部可以访问该页面。
     * 该页面调试工具请使用写文本函数logResult，该函数在com.alipay.util文件夹的AlipayNotify.java类文件中
     * 如果没有收到该页面返回的 success 信息，支付宝会在24小时内按一定的时间策略重发通知
     * TRADE_FINISHED(表示交易已经成功结束，为普通即时到帐的交易状态成功标识);
     * TRADE_SUCCESS(表示交易已经成功结束，为高级即时到帐的交易状态成功标识);
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException 
     */
    void alipayNotify(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("---------com.iwords.alipay.IWordsAlipayServlet.alipayNotify()");
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        System.out.println("---------com.iwords.alipay.IWordsAlipayServlet.alipayNotify() requestParams="+requestParams);
        if(requestParams != null){
            System.out.println("---------com.iwords.alipay.IWordsAlipayServlet.alipayNotify() requestParams.size()="+requestParams.size());
        }
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
            params.put(name, valueStr);
        }



        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//

        String trade_no = request.getParameter("trade_no");				//支付宝交易号
        String order_no = request.getParameter("out_trade_no");	        //获取订单号
        //String total_fee = request.getParameter("total_fee");	        //获取总金额
        //String subject = new String(request.getParameter("subject").getBytes("ISO-8859-1"), "utf-8");//商品名称、订单名称
        //String body = "";
        //if (request.getParameter("body") != null) {
        //    body = new String(request.getParameter("body").getBytes("ISO-8859-1"), "utf-8");//商品描述、订单备注、描述
        //}
        String buyer_email = request.getParameter("buyer_email");		//买家支付宝账号
        String trade_status = request.getParameter("trade_status");		//交易状态

        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//


        response.setContentType("text/html;charset=UTF-8");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        PrintWriter out = response.getWriter();
        try {
            if (AlipayNotify.verify(params)) {//验证成功
                //////////////////////////////////////////////////////////////////////////////////////////
                //请在这里加上商户的业务逻辑程序代码
                if(order_no != null){
                    AccountEntity account = accountService.find(Long.valueOf(order_no));
                    account.setAlipayNumber(trade_no);
                    account.setAlipayEmail(buyer_email);
                    accountService.edit(account);
                }
                //——请根据您的业务逻辑来编写程序（以下代码仅作参考）——

                if (trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {
                    //判断该笔订单是否在商户网站中已经做过处理（可参考“集成教程”中“3.4返回数据处理”）
                    //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                    //如果有做过处理，不执行商户的业务程序
                    AccountEntity account = new AccountEntity();
                    account.setId(Long.valueOf(order_no));
                    account.setAlipayEmail(buyer_email);
                    account.setAlipayNumber(trade_no);
                    if(accountService.updateAccountForAlipay(account)){
                         //更新session
                        Object o = request.getSession().getAttribute("user");
                        if(o!=null){
                            UserEntity user = (UserEntity)o;
                            user = userService.find(user.getUserid());
                            request.getSession().setAttribute("user", user);
                        }
                        out.println("success");	//请不要修改或删除
                    }else{
                         out.println("fail");
                    }

                    
                } else {
                    //参数错误
                    out.println("fail");	//请不要修改或删除
                }

                //——请根据您的业务逻辑来编写程序（以上代码仅作参考）——

            } else {//验证失败
                out.println("fail");
            }
        }catch(Exception e){
            log("回调异常",e);
            out.println("fail");
        }finally {
            out.close();
        }
    }
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">

    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
